﻿namespace SERFLITEMAX20.Viewer
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;

    public class ListViewSortManager
    {
        private const int HDF_BITMAP = 0x2000;
        private const int HDF_BITMAP_ON_RIGHT = 0x1000;
        private const int HDF_CENTER = 2;
        private const int HDF_IMAGE = 0x800;
        private const int HDF_JUSTIFYMASK = 3;
        private const int HDF_LEFT = 0;
        private const int HDF_OWNERDRAW = 0x8000;
        private const int HDF_RIGHT = 1;
        private const int HDF_RTLREADING = 4;
        private const int HDF_SORTDOWN = 0x200;
        private const int HDF_SORTUP = 0x400;
        private const int HDF_STRING = 0x4000;
        private const int HDI_BITMAP = 0x10;
        private const int HDI_DI_SETITEM = 0x40;
        private const int HDI_FILTER = 0x100;
        private const int HDI_FORMAT = 4;
        private const int HDI_HEIGHT = 1;
        private const int HDI_IMAGE = 0x20;
        private const int HDI_LPARAM = 8;
        private const int HDI_ORDER = 0x80;
        private const int HDI_TEXT = 2;
        private const int HDI_WIDTH = 1;
        private const int HDM_FIRST = 0x1200;
        private const int HDM_GETIMAGELIST = 0x1209;
        private const int HDM_GETITEM = 0x120b;
        private const int HDM_SETIMAGELIST = 0x1208;
        private const int HDM_SETITEM = 0x120c;
        private const int LVM_FIRST = 0x1000;
        private const int LVM_GETHEADER = 0x101f;
        private int m_column;
        private System.Type[] m_comparers;
        private ImageList m_imgList;
        private ListView m_list;
        private System.Windows.Forms.SortOrder m_sortOrder;
        private bool mSuspended;
        private static bool s_useNativeArrows = ComCtlDllSupportsArrows();

        public ListViewSortManager(ListView list, System.Type[] comparers) : this(list, comparers, -1, System.Windows.Forms.SortOrder.None)
        {
        }

        public ListViewSortManager(ListView list, System.Type[] comparers, int column, System.Windows.Forms.SortOrder order)
        {
            this.mSuspended = false;
            this.m_column = -1;
            this.m_sortOrder = System.Windows.Forms.SortOrder.None;
            this.m_list = list;
            this.m_comparers = comparers;
            if (!s_useNativeArrows)
            {
                this.m_imgList = new ImageList();
                this.m_imgList.ImageSize = new Size(8, 8);
                this.m_imgList.TransparentColor = Color.Magenta;
                this.m_imgList.Images.Add(this.GetArrowBitmap(ArrowType.Ascending));
                this.m_imgList.Images.Add(this.GetArrowBitmap(ArrowType.Descending));
                this.SetHeaderImageList(this.m_list, this.m_imgList);
            }
            list.ColumnClick += new ColumnClickEventHandler(this.ColumnClick);
            if (column != -1)
            {
                this.Sort(column, order);
            }
        }

        private void ColumnClick(object sender, ColumnClickEventArgs e)
        {
            this.Sort(e.Column);
        }

        private static bool ComCtlDllSupportsArrows()
        {
            bool flag;
            IntPtr zero = IntPtr.Zero;
            try
            {
                zero = LoadLibrary("comctl32.dll");
                if ((zero != IntPtr.Zero) && (GetProcAddress(zero, "DllGetVersion") == UIntPtr.Zero))
                {
                    return false;
                }
                DLLVERSIONINFO pdvi = new DLLVERSIONINFO();
                pdvi.cbSize = Marshal.SizeOf(typeof(DLLVERSIONINFO));
                DllGetVersion(ref pdvi);
                flag = pdvi.dwMajorVersion >= 6;
            }
            finally
            {
                if (zero != IntPtr.Zero)
                {
                    FreeLibrary(zero);
                }
            }
            return flag;
        }

        [DllImport("comctl32.dll")]
        private static extern int DllGetVersion(ref DLLVERSIONINFO pdvi);
        [DllImport("kernel32.dll")]
        private static extern bool FreeLibrary(IntPtr hModule);
        private Bitmap GetArrowBitmap(ArrowType type)
        {
            Bitmap image = new Bitmap(8, 8);
            Graphics graphics = Graphics.FromImage(image);
            Pen controlLightLight = SystemPens.ControlLightLight;
            Pen controlDark = SystemPens.ControlDark;
            graphics.FillRectangle(Brushes.Magenta, 0, 0, 8, 8);
            if (type == ArrowType.Ascending)
            {
                graphics.DrawLine(controlLightLight, 0, 7, 7, 7);
                graphics.DrawLine(controlLightLight, 7, 7, 4, 0);
                graphics.DrawLine(controlDark, 3, 0, 0, 7);
            }
            else if (type == ArrowType.Descending)
            {
                graphics.DrawLine(controlLightLight, 4, 7, 7, 0);
                graphics.DrawLine(controlDark, 3, 7, 0, 0);
                graphics.DrawLine(controlDark, 0, 0, 7, 0);
            }
            graphics.Dispose();
            return image;
        }

        public System.Type GetColumnComparerType(int column)
        {
            return this.m_comparers[column];
        }

        [DllImport("kernel32.dll", CharSet=CharSet.Ansi, ExactSpelling=true)]
        public static extern UIntPtr GetProcAddress(IntPtr hModule, string procName);
        [DllImport("kernel32.dll")]
        private static extern IntPtr LoadLibrary(string fileName);
        public void Resume()
        {
            this.mSuspended = false;
        }

        [DllImport("user32")]
        private static extern IntPtr SendMessage(IntPtr Handle, int msg, IntPtr wParam, IntPtr lParam);
        [DllImport("user32", EntryPoint="SendMessage")]
        private static extern IntPtr SendMessage2(IntPtr Handle, int msg, IntPtr wParam, ref HDITEM lParam);
        public void SetColumnComparerType(int column, System.Type comparerType)
        {
            this.m_comparers[column] = comparerType;
        }

        public void SetComparerTypes(System.Type[] comparers)
        {
            this.m_comparers = comparers;
        }

        private void SetHeaderImageList(ListView list, ImageList imgList)
        {
            SendMessage(SendMessage(list.Handle, 0x101f, IntPtr.Zero, IntPtr.Zero), 0x1208, IntPtr.Zero, imgList.Handle);
        }

        private void ShowHeaderIcon(ListView list, int columnIndex, System.Windows.Forms.SortOrder sortOrder)
        {
            if ((columnIndex >= 0) && (columnIndex < list.Columns.Count))
            {
                IntPtr handle = SendMessage(list.Handle, 0x101f, IntPtr.Zero, IntPtr.Zero);
                ColumnHeader header = list.Columns[columnIndex];
                HDITEM lParam = new HDITEM();
                lParam.mask = 4;
                HorizontalAlignment textAlign = header.TextAlign;
                if (textAlign == HorizontalAlignment.Left)
                {
                    lParam.fmt = 0x5000;
                }
                else if (textAlign == HorizontalAlignment.Center)
                {
                    lParam.fmt = 0x5002;
                }
                else
                {
                    lParam.fmt = 0x4001;
                }
                if (s_useNativeArrows)
                {
                    if (sortOrder == System.Windows.Forms.SortOrder.Ascending)
                    {
                        lParam.fmt |= 0x400;
                    }
                    else if (sortOrder == System.Windows.Forms.SortOrder.Descending)
                    {
                        lParam.fmt |= 0x200;
                    }
                }
                else
                {
                    lParam.mask |= 0x20;
                    if (sortOrder != System.Windows.Forms.SortOrder.None)
                    {
                        lParam.fmt |= 0x800;
                    }
                    lParam.iImage = ((int) sortOrder) - 1;
                }
                SendMessage2(handle, 0x120c, new IntPtr(columnIndex), ref lParam);
            }
        }

        public void Sort(int column)
        {
            System.Windows.Forms.SortOrder ascending = System.Windows.Forms.SortOrder.Ascending;
            if (column == this.m_column)
            {
                ascending = (this.m_sortOrder == System.Windows.Forms.SortOrder.Ascending) ? System.Windows.Forms.SortOrder.Descending : System.Windows.Forms.SortOrder.Ascending;
            }
            this.Sort(column, ascending);
        }

        public void Sort(int column, System.Windows.Forms.SortOrder order)
        {
            if (!this.mSuspended)
            {
                if ((column < 0) || (column >= this.m_comparers.Length))
                {
                    throw new IndexOutOfRangeException();
                }
                if (column != this.m_column)
                {
                    this.ShowHeaderIcon(this.m_list, this.m_column, System.Windows.Forms.SortOrder.None);
                    this.m_column = column;
                }
                this.ShowHeaderIcon(this.m_list, this.m_column, order);
                this.m_sortOrder = order;
                if (this.m_sortOrder != System.Windows.Forms.SortOrder.None)
                {
                    if (this.m_comparers[this.m_column] != null)
                    {
                        ListViewTextSort sort = (ListViewTextSort) Activator.CreateInstance(this.m_comparers[this.m_column], new object[] { this.m_column, this.m_sortOrder == System.Windows.Forms.SortOrder.Ascending });
                        SortedList<string, Queue<ListViewItem>> list = new SortedList<string, Queue<ListViewItem>>();
                        foreach (ListViewItem item in this.m_list.Items)
                        {
                            if (item.Group != null)
                            {
                                if (!list.ContainsKey(item.Group.Name))
                                {
                                    list.Add(item.Group.Name, new Queue<ListViewItem>());
                                }
                                list[item.Group.Name].Enqueue(item);
                                item.Group = null;
                            }
                        }
                        this.m_list.ListViewItemSorter = sort;
                        foreach (string str in list.Keys)
                        {
                            Queue<ListViewItem> queue = list[str];
                            ListViewGroup group = this.m_list.Groups[str];
                            foreach (ListViewItem item in queue)
                            {
                                item.Group = group;
                            }
                        }
                    }
                }
                else
                {
                    this.m_list.ListViewItemSorter = null;
                }
            }
        }

        public void Suspend()
        {
            this.m_list.ListViewItemSorter = null;
        }

        public int Column
        {
            get
            {
                return this.m_column;
            }
        }

        public bool SortEnabled
        {
            get
            {
                return (this.m_list.ListViewItemSorter != null);
            }
            set
            {
                if (value)
                {
                    if (!this.SortEnabled)
                    {
                        this.m_list.ColumnClick += new ColumnClickEventHandler(this.ColumnClick);
                        this.m_list.ListViewItemSorter = (ListViewTextSort) Activator.CreateInstance(this.m_comparers[this.m_column], new object[] { this.m_column, this.m_sortOrder == System.Windows.Forms.SortOrder.Ascending });
                        this.ShowHeaderIcon(this.m_list, this.m_column, this.m_sortOrder);
                    }
                }
                else if (this.SortEnabled)
                {
                    this.m_list.ColumnClick -= new ColumnClickEventHandler(this.ColumnClick);
                    this.m_list.ListViewItemSorter = null;
                    this.ShowHeaderIcon(this.m_list, this.m_column, System.Windows.Forms.SortOrder.None);
                }
            }
        }

        public System.Windows.Forms.SortOrder SortOrder
        {
            get
            {
                return this.m_sortOrder;
            }
        }

        private enum ArrowType
        {
            Ascending,
            Descending
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct DLLVERSIONINFO
        {
            public int cbSize;
            public int dwMajorVersion;
            public int dwMinorVersion;
            public int dwBuildNumber;
            public int dwPlatformID;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct HDITEM
        {
            public int mask;
            public int cxy;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string pszText;
            public IntPtr hbm;
            public int cchTextMax;
            public int fmt;
            public int lParam;
            public int iImage;
            public int iOrder;
        }
    }
}

